/** @jsxImportSource @emotion/react */
import React, {
    Children,
    cloneElement,
    forwardRef,
    isValidElement, MouseEventHandler,
    useEffect,
    useMemo,
    useRef,
    useState
} from "react";
import {jsx,css} from "@emotion/react";
import {
    useFloating,
    offset,
    flip,
    shift,
    useListNavigation,
    useHover,
    useTypeahead,
    useInteractions,
    useRole,
    useClick,
    useDismiss,
    autoUpdate,
    safePolygon,
    FloatingPortal,
    useFloatingTree,
    useFloatingNodeId,
    useFloatingParentNodeId,
    FloatingNode,
    FloatingTree,
    FloatingFocusManager, useMergeRefs
} from "@floating-ui/react";
import cx from "classnames";
// import { mergeRefs } from "react-merge-refs";
// import {useTheme} from "./Theme/Providers";
// import {MenuItem} from "./Menu";

import {
    useTheme, MenuItem
} from "customize-easy-ui-component";



/*直接改造 源自官方例子的： https://codesandbox.io/s/admiring-lamport-5wt3yg?file=/src/DropdownMenu.tsx
样式直接文件注入的形式：
原来例子 import "./styles.css";
* */


/** 叶子节点的菜单项目； 必须放在DdMenu下面的；
 注意这样的 <DdMenu label="菜单"  icon={<IconMoreVertical />}>
 <React.Fragment>
 <DdMenuItem label="Undo" />
 【特别注意】多套一层<></>就无法正常工作的。
 # 若有children儿子的就显示为儿子。否则就按照label显示的。 两个情况的样式控制不同。
 实际上：forwardRef<T, P = {}> 在P模型中定义onClick是关键触发！
 * */
export const DdMenuItem = forwardRef< HTMLButtonElement,
    {
        label: string;
        disabled?: boolean;
        onClick?: MouseEventHandler | undefined;
        children?: React.ReactNode;
        onPress?: MouseEventHandler | undefined;     //可兼容性
        contentAfter?: React.ReactNode;
        contentBefore?: React.ReactNode;      //前置的图标按钮<MenuItem透传参数;
    }
    >((
    {  label,
        disabled,
        //onClick,
        children,
        ...props
    }, ref
) => {

    //支持嵌套组件的属性参数透明传递：  {...props}  方式就可以传递 css= style= 儿子组件 等。类似{... other}做法的...bind()。
    //const { getItemProps } = useInteractions();
    //【特别注意】元素的tag标签对样式影响大component={"div"} #={"button"} 用div更好；
    //底下<MenuItem ref= 实际可以加上{ ...getItemProps({ onClick,  style: { },  }) }的。
    return (
        <MenuItem
            ref={ref}
            role="menuitem"
            disabled={disabled}
            style={{       //MenuItem#
                display: 'flex',
            }}
            css={{
                //maxWidth: '10rem',         不灵活的
                background:  'ghostwhite',
                ":focus,:not([disabled]):active": {          //点亮的
                    //color: 'red',
                    background:  'mistyrose'
                },
            }}

            {...props}
        >
            {children? children : label }
        </MenuItem>
    );
});

//无需要公开的external ?
interface MenuProps {
    //可支持搜索菜单项目的 文本。
    label?: string;
    //实际 没必要的参数
    nested?: boolean;
    children?: React.ReactNode;
    //后面安放的图标
    // contentAfter?: React.ReactNode;
    //前面安放的图标
    //  contentBefore?: React.ReactNode;
    //任意的组件， 简易按钮 图标
    icon?: React.ReactNode;
    //菜单按钮的样式 ：还是能独立配置为佳。
    divStyle?: React.CSSProperties;
    /**可以将这里没定义的参数 tight={true} 透明传递下去。
     * */
    [key: string]: any;     //任意参数传递模式！
}

/**不是叶子的节点菜单项。根部或者嵌套的树杈按钮。
 * 注意icon有没有会影响到树杈或者根部按钮菜单项的高度！icon决定了到底是string纯粹文本的，还是嵌套div组件图标按钮的。
 * 若有icon={}的就显示为图标组件。否则就按照label显示的。 两个情况的样式控制不同。
 * */
export const MenuComponent = forwardRef<
    HTMLButtonElement,
    MenuProps & React.HTMLProps<HTMLButtonElement>
    >(({
           icon,
           children,
           label,
           divStyle,
           ...props }, forwardedRef
) => {
    const theme = useTheme();
    const [open, setOpen] = useState(false);
    const [activeIndex, setActiveIndex] = useState<number | null>(null);
    const [allowHover, setAllowHover] = useState(false);

    const listItemsRef = useRef<Array<HTMLButtonElement | null>>([]);
    const listContentRef = useRef(
        Children.map(children, (child) =>
            isValidElement(child) ? child.props.label : null
        ) as Array<string | null>
    );

    const tree = useFloatingTree();
    const nodeId = useFloatingNodeId();
    const parentId = useFloatingParentNodeId();
    //不是嵌套的树杈节点，就是树根root的：
    const nested = parentId != null;

    const { x, y, reference, floating, strategy,  context } = useFloating<
        HTMLButtonElement
        >({
        open,
        nodeId,
        onOpenChange: setOpen,
        middleware: [
            offset({ mainAxis: 4, alignmentAxis: nested ? -5 : 0 }),
            flip(),
            shift()
        ],
        placement: nested ? "right-start" : "bottom-start",
        whileElementsMounted: autoUpdate
    });

    const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(
        [
            useHover(context, {
                handleClose: safePolygon({ restMs: 25 }),
                enabled: nested && allowHover,
                delay: { open: 75 }
            }),
            useClick(context, {
                toggle: !nested || !allowHover,
                event: "mousedown",
                ignoreMouse: nested && allowHover
            }),
            useRole(context, { role: "menu" }),
            useDismiss(context),
            useListNavigation(context, {
                listRef: listItemsRef,
                activeIndex,
                nested,
                onNavigate: setActiveIndex
            }),
            useTypeahead(context, {
                listRef: listContentRef,
                onMatch: open ? setActiveIndex : undefined,
                activeIndex
            })
        ]
    );

    // Event emitter allows you to communicate across tree components.
    // This effect closes all menus when an item gets clicked anywhere
    // in the tree.
    React.useEffect(() => {
        function handleTreeClick() {
            setOpen(false);
        }

        tree?.events.on("click", handleTreeClick);
        return () => {
            tree?.events.off("click", handleTreeClick);
        };
    }, [tree]);

    // Determine if "hover" logic can run based on the modality of input. This
    // prevents unwanted focus synchronization as menus open and close with
    // keyboard navigation and the cursor is resting on the menu.
    React.useEffect(() => {
        function onPointerMove({ pointerType }: PointerEvent) {
            if (pointerType !== "touch") {
                setAllowHover(true);
            }
        }

        function onKeyDown() {
            setAllowHover(false);
        }

        window.addEventListener("pointermove", onPointerMove, {
            once: true,
            capture: true
        });
        window.addEventListener("keydown", onKeyDown, true);
        return () => {
            window.removeEventListener("pointermove", onPointerMove, {
                capture: true
            });
            window.removeEventListener("keydown", onKeyDown, true);
        };
    }, [allowHover]);

    const referenceRef = useMergeRefs([reference, forwardedRef]);

    // const mergedReferenceRef = useMemo(() => mergeRefs([ref, reference]), [
    //     reference,
    //     ref
    // ]);

    //底下的<MenuItem {...props } 注意优先级替换配置，才能把外部样式css={ {的都注入进来。
    //从上级<DdMenu接收 tight={true} 参数 到...props,  然后传递给了<MenuItem ；
    return (
        <FloatingNode id={nodeId}>

            <MenuItem
                ref={referenceRef}
                {...getReferenceProps({
                    ...props,
                    className: `${nested ? "MenuItem" : "RootMenu"}${
                        open ? " open" : ""
                    }`,
                    onClick(event) {
                        event.stopPropagation();
                    },
                    ...(nested && {
                        // Indicates this is a nested <Menu /> acting as a <MenuItem />.
                        role: "menuitem"
                    })
                })}
                css={{
                    justifyContent: 'space-between',
                    ":hover": {
                        //color: 'blue',
                    },
                    ...divStyle,
                }}
            >
                {icon && icon}
                {!icon && label} {!icon && nested && <span aria-hidden style={{ marginLeft: 11 }}>➔</span>}
            </MenuItem>

            <FloatingPortal>
                {open && (
                    <FloatingFocusManager
                        context={context}
                        // Prevent outside content interference.
                        modal={!nested}
                        // Only initially focus the root floating menu.
                        initialFocus={nested ? -1 : 0}
                        // Only return focus to the root menu's reference when menus close.
                        returnFocus={!nested}
                        // Allow touch screen readers to escape the modal root menu
                        // without selecting anything.
                        visuallyHiddenDismiss
                    >
                        <div
                            ref={floating}
                            className="MGroup"
                             style={{
                             }}
                             {...getFloatingProps({
                                 style: {
                                     position: strategy,
                                     top: y ?? 0,
                                     left: x ?? 0,
                                     zIndex: theme.zIndices.menus,     //若遭遇iframe的窗口大小，还是无法突破的，受限iframe。
                                     background: 'white',
                                     boxShadow: theme.shadows["md"],
                                     borderRadius: theme.radii.md
                                 },
                                 onKeyDown(event) {
                                     if (event.key === "Tab") {
                                         setOpen(false);
                                     }
                                 },
                             })}
                        >
                            {Children.map(
                                children,
                                (child, index) =>
                                    isValidElement(child) &&
                                    cloneElement(
                                        child,
                                        getItemProps({
                                            tabIndex: activeIndex === index ? 0 : -1,
                                            role: "menuitem",
                                            className: "MenuItem",
                                            ref(node: HTMLButtonElement) {
                                                listItemsRef.current[index] = node;
                                            },
                                            onClick(e) {
                                                e.stopPropagation();
                                                // console.log("Press菜单项前");
                                                if(!child.props.disabled && child.props.onClick)
                                                    child.props.onClick(e);
                                                tree?.events.emit("click");
                                            },
                                            // By default `focusItemOnHover` uses `mousemove` to sync focus,
                                            // but when a menu closes we want this to sync it on `enter`
                                            // even if the cursor didn't move. NB: Safari does not sync in
                                            // this case.
                                            onPointerEnter() {
                                                if (allowHover) {
                                                    setActiveIndex(index);
                                                }
                                            },
                                            style: {
                                                //lineHeight: '4.0',纯文本不会被这个约束！只有父辈树杈按钮有icon={}的才会被影响。
                                            },
                                        })
                                    )
                            )}
                        </div>
                    </FloatingFocusManager>
                )}
            </FloatingPortal>
        </FloatingNode>
    );
});

/**根部或者嵌套分支的菜单项： 可自由互动布局的 菜单；
 <DdMenu>和 <DdMenuItem>不能够拆解分开！｛｝传递组件参数时要注意。
 【注意】icon={}属性可以直接头传给儿子组件<MenuComponent >的，
 <DdMenu label="菜单" divStyle={{ lineHeight: '1.0'} }>
 纯文本树杈根部按钮可以用 divStyle={{ lineHeight: '1.0'} } 来修正样式控制的，若有参数icon={}就不同了。
 例子<DdMenu label="搜索文字"  icon={
      <MenuItem variant="ghost">
          <IconMoreVertical />
      </MenuItem>
  }>  <DdMenuItem...个的  </DdMenu>
 * */
export const DdMenu = React.forwardRef<
    HTMLButtonElement,
    MenuProps & React.HTMLProps<HTMLButtonElement>
    >((props, ref) => {

        const parentId = useFloatingParentNodeId();

        //支持嵌套组件的属性参数透明传递：  {...props}  方式就可以传递 icon={} css= style= 儿子组件 等。
        if (parentId == null) {
            return (
                <FloatingTree>
                    <MenuComponent {...props} ref={ref}
                    />
                </FloatingTree>
            );
        }

        return <MenuComponent {...props} ref={ref}
        />;
    } );



/* 样式例子
   css={{
       "&.active": {
           fontSize: '32px',
       },
       ":hover": {
           background: 'green',
           fontSize: '32px',
       }
   }}
* */
